<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc,fixuphtml" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <title>Java Object Serialization Specification: 2 - Object Output Classes</title>
  <style type="text/css">
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
  </style>
  <link rel="stylesheet" href="../../resources/jdk-default.css" />
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<header id="title-block-header">
<h1 class="title">Java Object Serialization Specification: 2 - Object Output Classes</h1>
</header>
<main><ul>
<li><a href="#the-objectoutputstream-class">The ObjectOutputStream Class</a></li>
<li><a href="#the-objectoutputstream.putfield-class">The ObjectOutputStream.PutField Class</a></li>
<li><a href="#the-writeobject-method">The writeObject Method</a></li>
<li><a href="#the-writeexternal-method">The writeExternal Method</a></li>
<li><a href="#the-writereplace-method">The writeReplace Method</a></li>
<li><a href="#the-useprotocolversion-method">The useProtocolVersion Method</a></li>
</ul>
<hr />
<h2 id="the-objectoutputstream-class">2.1 The ObjectOutputStream Class</h2>
<p>Class <code>ObjectOutputStream</code> implements object serialization. It maintains the state of the stream including the set of objects already serialized. Its methods control the traversal of objects to be serialized to save the specified objects and the objects to which they refer.</p>
<pre><code>package java.io;

public class ObjectOutputStream
    extends OutputStream
    implements ObjectOutput, ObjectStreamConstants
{
    public ObjectOutputStream(OutputStream out)
        throws IOException;

    public final void writeObject(Object obj)
        throws IOException;

    public void writeUnshared(Object obj)
        throws IOException;

    public void defaultWriteObject()
        throws IOException, NotActiveException;

    public PutField putFields()
        throws IOException;

    public void writeFields()
        throws IOException;

    public void reset() throws IOException;

    protected void annotateClass(Class&lt;?&gt; cl) throws IOException;

    protected void annotateProxyClass(Class&lt;?&gt; cl) throws IOException;

    protected void writeClassDescriptor(ObjectStreamClass desc)
        throws IOException;

    protected Object replaceObject(Object obj) throws IOException;

    protected boolean enableReplaceObject(boolean enable)
        throws SecurityException;

    protected void writeStreamHeader() throws IOException;

    public void write(int data) throws IOException;

    public void write(byte b[]) throws IOException;

    public void write(byte b[], int off, int len) throws IOException;

    public void flush() throws IOException;

    protected void drain() throws IOException;

    public void close() throws IOException;

    public void writeBoolean(boolean data) throws IOException;

    public void writeByte(int data) throws IOException;

    public void writeShort(int data) throws IOException;

    public void writeChar(int data) throws IOException;

    public void writeInt(int data) throws IOException;

    public void writeLong(long data) throws IOException;

    public void writeFloat(float data) throws IOException;

    public void writeDouble(double data) throws IOException;

    public void writeBytes(String data) throws IOException;

    public void writeChars(String data) throws IOException;

    public void writeUTF(String data) throws IOException;

    // Inner class to provide access to serializable fields.
    public abstract static class PutField
    {
        public void put(String name, boolean value)
            throws IllegalArgumentException;

        public void put(String name, char data)
            throws IllegalArgumentException;

        public void put(String name, byte data)
            throws IllegalArgumentException;

        public void put(String name, short data)
            throws IllegalArgumentException;

        public void put(String name, int data)
            throws IllegalArgumentException;

        public void put(String name, long data)
            throws IllegalArgumentException;

        public void put(String name, float data)
            throws IllegalArgumentException;

        public void put(String name, double data)
            throws IllegalArgumentException;

        public void put(String name, Object data)
            throws IllegalArgumentException;
    }

    public void useProtocolVersion(int version) throws IOException;

    protected ObjectOutputStream()
        throws IOException;

    protected writeObjectOverride()
        throws NotActiveException, IOException;
}</code></pre>
<p>The single-argument <code>ObjectOutputStream</code> constructor creates an <code>ObjectOutputStream</code> that serializes objects to the given <code>OutputStream</code>. The constructor calls <code>writeStreamHeader</code> to write a magic number and version to the stream that will be read and verified by a corresponding call to <code>readStreamHeader</code> in the single-argument <code>ObjectInputStream</code> constructor. If a security manager is installed, this constructor checks for the <code>&quot;enableSubclassImplementation&quot;</code> <code>SerializablePermission</code> when invoked directly or indirectly by the constructor of a subclass which overrides the <code>putFields</code> and/or <code>writeUnshared</code> methods.</p>
<p>The <code>writeObject</code> method is used to serialize an object to the stream. An object is serialized as follows:</p>
<ol type="1">
<li><p>If a subclass is overriding the implementation, call the <code>writeObjectOverride</code> method and return. Overriding the implementation is described at the end of this section.</p></li>
<li><p>If there is data in the block-data buffer, the data is written to the stream and the buffer is reset.</p></li>
<li><p>If the object is null, null is put in the stream and <code>writeObject</code> returns.</p></li>
<li><p>If the object has been previously replaced, as described in Step 8, write the handle of the replacement to the stream and <code>writeObject</code> returns.</p></li>
<li><p>If the object has already been written to the stream, its handle is written to the stream and <code>writeObject</code> returns.</p></li>
<li><p>If the object is a <code>Class</code>, the corresponding <code>ObjectStreamClass</code> is written to the stream, a handle is assigned for the class, and <code>writeObject</code> returns.</p></li>
<li><p>If the object is an <code>ObjectStreamClass</code>, a handle is assigned to the object, after which it is written to the stream using one of the class descriptor formats described in <a href="class.html#serialized-form">Section 4.3, &quot;Serialized Form&quot;</a>. In versions 1.3 and later of the Java 2 SDK, Standard Edition, the <code>writeClassDescriptor</code> method is called to output the <code>ObjectStreamClass</code> if it represents a class that is not a dynamic proxy class, as determined by passing the associated <code>Class</code> object to the <code>isProxyClass</code> method of <code>java.lang.reflect.Proxy</code>. Afterwards, an annotation for the represented class is written: if the class is a dynamic proxy class, then the <code>annotateProxyClass</code> method is called; otherwise, the <code>annotateClass</code> method is called. The <code>writeObject</code> method then returns.</p></li>
<li><p>Process potential substitutions by the class of the object and/or by a subclass of <code>ObjectInputStream</code>.</p>
<ol type="a">
<li><p>If the class of an object is not an enum type and defines the appropriate <code>writeReplace</code> method, the method is called. Optionally, it can return a substitute object to be serialized.</p></li>
<li><p>Then, if enabled by calling the <code>enableReplaceObject</code> method, the <code>replaceObject</code> method is called to allow subclasses of <code>ObjectOutputStream</code> to substitute for the object being serialized. If the original object was replaced in the previous step, the <code>replaceObject</code> method is called with the replacement object.</p></li>
</ol>
<p>If the original object was replaced by either one or both steps above, the mapping from the original object to the replacement is recorded for later use in Step 4. Then, Steps 3 through 7 are repeated on the new object.</p>
<p>If the replacement object is not one of the types covered by Steps 3 through 7, processing resumes using the replacement object at Step 10.</p></li>
<li><p><a id="java-lang-string-encoding"></a> If the object is a <code>java.lang.String,</code> the string is written as length information followed by the contents of the string encoded in modified UTF-8. For details, refer to <a href="protocol.html#stream-elements">Section 6.2, &quot;Stream Elements&quot;</a>. A handle is assigned to the string, and <code>writeObject</code> returns.</p></li>
<li><p>If the object is an array, <code>writeObject</code> is called recursively to write the <code>ObjectStreamClass</code> of the array. The handle for the array is assigned. It is followed by the length of the array. Each element of the array is then written to the stream, after which <code>writeObject</code> returns.</p></li>
<li><p>If the object is an enum constant, the <code>ObjectStreamClass</code> for the enum type of the constant is written by recursively calling <code>writeObject</code>. It will appear in the stream only the first time it is referenced. A handle is assigned for the enum constant. Next, the value returned by the <code>name</code> method of the enum constant is written as a <code>String</code> object, as described in step 9. Note that if the same name string has appeared previously in the stream, a back reference to it will be written. The <code>writeObject</code> method then returns.</p></li>
<li><p>If the object is a record object, the <code>ObjectStreamClass</code> for the class of the record object is written by recursively calling <code>writeObject</code>. It will appear in the stream only the first time it is referenced. A handle is assigned for the record object.</p>
<p>The components of the record object are written to the stream.</p>
<pre><code> a.  If the record object is serializable or externalizable, the record
     components are written, as if by invoking the `defaultWriteObject`
     method.

 b.  If the object is neither serializable or externalizable, the
     `NotSerializableException` is thrown.</code></pre>
<p>The <code>writeObject</code> method then returns.</p></li>
<li><p>For regular objects, the <code>ObjectStreamClass</code> for the class of the object is written by recursively calling <code>writeObject</code>. It will appear in the stream only the first time it is referenced. A handle is assigned for the object.</p>
<p>The contents of the object are written to the stream.</p>
<pre><code>a.  If the object is serializable, the highest serializable class is
    located. For that class, and each derived class, that class&#39;s fields
    are written. If the class does not have a `writeObject` method, the
    `defaultWriteObject` method is called to write the serializable fields
    to the stream. If the class does have a `writeObject` method, it is
    called. It may call `defaultWriteObject` or `putFields` and
    `writeFields` to save the state of the object, and then it can write
    other information to the stream.

b.  If the object is externalizable, the `writeExternal` method of the
    object is called.

c.  If the object is neither serializable or externalizable, the
    `NotSerializableException` is thrown.</code></pre></li>
</ol>
<p>Exceptions may occur during the traversal or may occur in the underlying stream. For any subclass of <code>IOException</code>, the exception is written to the stream using the exception protocol and the stream state is discarded. If a second <code>IOException</code> is thrown while attempting to write the first exception into the stream, the stream is left in an unknown state and <code>StreamCorruptedException</code> is thrown from <code>writeObject</code>. For other exceptions, the stream is aborted and left in an unknown and unusable state.</p>
<p>The <code>writeUnshared</code> method writes an &quot;unshared&quot; object to the <code>ObjectOutputStream</code>. This method is identical to <code>writeObject</code>, except that it always writes the given object as a new, unique object in the stream (as opposed to a back-reference pointing to a previously serialized instance). Specifically:</p>
<ul>
<li><p>An object written via <code>writeUnshared</code> is always serialized in the same manner as a newly appearing object (an object that has not been written to the stream yet), regardless of whether or not the object has been written previously.</p></li>
<li><p>If <code>writeObject</code> is used to write an object that has been previously written with <code>writeUnshared</code>, the previous <code>writeUnshared</code> operation is treated as if it were a write of a separate object. In other words, <code>ObjectOutputStream</code> will never generate back-references to object data written by calls to <code>writeUnshared</code>.</p></li>
</ul>
<p>While writing an object via <code>writeUnshared</code> does not in itself guarantee a unique reference to the object when it is deserialized, it allows a single object to be defined multiple times in a stream, so that multiple calls to the <code>ObjectInputStream.readUnshared</code> method (see <a href="input.html#the-objectinputstream-class">Section 3.1, &quot;The ObjectInputStream Class&quot;</a>) by the receiver will not conflict. Note that the rules described above only apply to the base-level object written with <code>writeUnshared</code>, and not to any transitively referenced sub-objects in the object graph to be serialized.</p>
<p>The <code>defaultWriteObject</code> method implements the default serialization mechanism for the current class. This method may be called only from a class's <code>writeObject</code> method. The method writes all of the serializable fields of the current class to the stream. If called from outside the <code>writeObject</code> method, the <code>NotActiveException</code> is thrown.</p>
<p>The <code>putFields</code> method returns a <code>PutField</code> object the caller uses to set the values of the serializable fields in the stream. The fields may be set in any order. After all of the fields have been set, <code>writeFields</code> must be called to write the field values in the canonical order to the stream. If a field is not set, the default value appropriate for its type will be written to the stream. This method may only be called from within the <code>writeObject</code> method of a serializable class. It may not be called more than once or if <code>defaultWriteObject</code> has been called. Only after <code>writeFields</code> has been called can other data be written to the stream.</p>
<p>The <code>reset</code> method resets the stream state to be the same as if it had just been constructed. <code>Reset</code> will discard the state of any objects already written to the stream. The current point in the stream is marked as reset, so the corresponding <code>ObjectInputStream</code> will reset at the same point. Objects previously written to the stream will not be remembered as already having been written to the stream. They will be written to the stream again. This is useful when the contents of an object or objects must be sent again. <code>Reset</code> may not be called while objects are being serialized. If called inappropriately, an <code>IOException</code> is thrown.</p>
<p>Starting with the Java 2 SDK, Standard Edition, v1.3, the <code>writeClassDescriptor</code> method is called when an <code>ObjectStreamClass</code> needs to be serialized. <code>writeClassDescriptor</code> is responsible for writing a representation of the <code>ObjectStreamClass</code> to the serialization stream. Subclasses may override this method to customize the way in which class descriptors are written to the serialization stream. If this method is overridden, then the corresponding <code>readClassDescriptor</code> method in <code>ObjectInputStream</code> should also be overridden to reconstitute the class descriptor from its custom stream representation. By default, <code>writeClassDescriptor</code> writes class descriptors according to the format specified in <a href="protocol.html#grammar-for-the-stream-format">Section 6.4, &quot;Grammar for the Stream Format&quot;</a>. Note that this method will only be called if the <code>ObjectOutputStream</code> is not using the old serialization stream format (see <a href="protocol.html#stream-protocol-versions">Section 6.3, &quot;Stream Protocol Versions&quot;</a>). If the serialization stream is using the old format (<code>ObjectStreamConstants.PROTOCOL_VERSION_1</code>), the class descriptor will be written internally in a manner that cannot be overridden or customized.</p>
<p>The <code>annotateClass</code> method is called while a <code>Class</code> is being serialized, and after the class descriptor has been written to the stream. Subclasses may extend this method and write other information to the stream about the class. This information must be read by the <code>resolveClass</code> method in a corresponding <code>ObjectInputStream</code> subclass.</p>
<p>An <code>ObjectOutputStream</code> subclass can implement the <code>replaceObject</code> method to monitor or replace objects during serialization. Replacing objects must be enabled explicitly by calling <code>enableReplaceObject</code> before calling <code>writeObject</code> with the first object to be replaced. Once enabled, <code>replaceObject</code> is called for each object just prior to serializing the object for the first time. Note that the <code>replaceObject</code> method is not called for objects of the specially handled classes, <code>Class</code> and <code>ObjectStreamClass</code>. An implementation of a subclass may return a substitute object that will be serialized instead of the original. The substitute object must be serializable. All references in the stream to the original object will be replaced by the substitute object.</p>
<p>When objects are being replaced, the subclass must ensure that the substituted object is compatible with every field where the reference will be stored, or that a complementary substitution will be made during deserialization. Objects, whose type is not a subclass of the type of the field or array element, will later abort the deserialization by raising a <code>ClassCastException</code> and the reference will not be stored.</p>
<p>The <code>enableReplaceObject</code> method can be called by trusted subclasses of <code>ObjectOutputStream</code> to enable the substitution of one object for another during serialization. Replacing objects is disabled until <code>enableReplaceObject</code> is called with a <code>true</code> value. It may thereafter be disabled by setting it to <code>false</code>. The previous setting is returned. The <code>enableReplaceObject</code> method checks that the stream requesting the replacement can be trusted. To ensure that the private state of objects is not unintentionally exposed, only trusted stream subclasses may use <code>replaceObject</code>. Trusted classes are those classes that belong to a security protection domain with permission to enable Serializable substitution.</p>
<p>If the subclass of <code>ObjectOutputStream</code> is not considered part of the system domain, <code>SerializablePermission &quot;enableSubstitution&quot;</code> must be added to the security policy file. <code>AccessControlException</code> is thrown if the protection domain of the subclass of <code>ObjectInputStream</code> does not have permission to <code>&quot;enableSubstitution&quot;</code> by calling <code>enableReplaceObject</code>. See the document Java Security Architecture (JDK1.2) for additional information about the security model.</p>
<p>The <code>writeStreamHeader</code> method writes the magic number and version to the stream. This information must be read by the <code>readStreamHeader</code> method of <code>ObjectInputStream</code>. Subclasses may need to implement this method to identify the stream's unique format.</p>
<p>The <code>flush</code> method is used to empty any buffers being held by the stream and to forward the flush to the underlying stream. The <code>drain</code> method may be used by subclassers to empty only the <code>ObjectOutputStream</code>'s buffers without forcing the underlying stream to be flushed.</p>
<p>All of the write methods for primitive types encode their values using a <code>DataOutputStream</code> to put them in the standard stream format. The bytes are buffered into block data records so they can be distinguished from the encoding of objects. This buffering allows primitive data to be skipped if necessary for class versioning. It also allows the stream to be parsed without invoking class-specific methods.</p>
<p>To override the implementation of serialization, the subclass of <code>ObjectOutputStream</code> should call the protected no-arg <code>ObjectOutputStream</code>, constructor. There is a security check within the no-arg constructor for <code>SerializablePermission &quot;enableSubclassImplementation&quot;</code> to ensure that only trusted classes are allowed to override the default implementation. This constructor does not allocate any private data for <code>ObjectOutputStream</code> and sets a flag that indicates that the final <code>writeObject</code> method should invoke the <code>writeObjectOverride</code> method and return. All other <code>ObjectOutputStream</code> methods are not final and can be directly overridden by the subclass.</p>
<h2 id="the-objectoutputstream.putfield-class">2.2 The ObjectOutputStream.PutField Class</h2>
<p>Class <code>PutField</code> provides the API for setting values of the serializable fields for a class when the class does not use default serialization. Each method puts the specified named value into the stream. An <code>IllegalArgumentException</code> is thrown if <code>name</code> does not match the name of a serializable field for the class whose fields are being written, or if the type of the named field does not match the second parameter type of the specific <code>put</code> method invoked.</p>
<h2 id="the-writeobject-method">2.3 The writeObject Method</h2>
<p>For serializable objects, the <code>writeObject</code> method allows a class to control the serialization of its own fields. Here is its signature:</p>
<pre><code>private void writeObject(ObjectOutputStream stream)
    throws IOException;</code></pre>
<p>Each subclass of a serializable object may define its own <code>writeObject</code> method. If a class does not implement the method, the default serialization provided by <code>defaultWriteObject</code> will be used. When implemented, the class is only responsible for writing its own fields, not those of its supertypes or subtypes.</p>
<p>The class's <code>writeObject</code> method, if implemented, is responsible for saving the state of the class. Either <code>ObjectOutputStream</code>'s <code>defaultWriteObject</code> or <code>writeFields</code> method must be called once (and only once) before writing any optional data that will be needed by the corresponding <code>readObject</code> method to restore the state of the object; even if no optional data is written, <code>defaultWriteObject</code> or <code>writeFields</code> must still be invoked once. If <code>defaultWriteObject</code> or <code>writeFields</code> is not invoked once prior to the writing of optional data (if any), then the behavior of instance deserialization is undefined in cases where the <code>ObjectInputStream</code> cannot resolve the class which defined the <code>writeObject</code> method in question.</p>
<p>The responsibility for the format, structure, and versioning of the optional data lies completely with the class.</p>
<h2 id="the-writeexternal-method">2.4 The writeExternal Method</h2>
<p>Objects implementing <code>java.io.Externalizable</code> must implement the <code>writeExternal</code> method to save the entire state of the object. It must coordinate with its superclasses to save their state. All of the methods of <code>ObjectOutput</code> are available to save the object's primitive typed fields and object fields.</p>
<pre><code>public void writeExternal(ObjectOutput stream)
    throws IOException;</code></pre>
<p>A new default format for writing Externalizable data has been introduced in JDK 1.2. The new format specifies that primitive data will be written in block data mode by <code>writeExternal</code> methods. Additionally, a tag denoting the end of the External object is appended to the stream after the <code>writeExternal</code> method returns. The benefits of this format change are discussed in <a href="input.html#the-readexternal-method">Section 3.6, &quot;The readExternal Method&quot;</a>. Compatibility issues caused by this change are discussed in <a href="#the-useprotocolversion-method">Section 2.6, &quot;The useProtocolVersion Method&quot;</a>.</p>
<h2 id="the-writereplace-method">2.5 The writeReplace Method</h2>
<p>For Serializable and Externalizable classes, the <code>writeReplace</code> method allows a class of an object to nominate its own replacement in the stream before the object is written. By implementing the <code>writeReplace</code> method, a class can directly control the types and instances of its own instances being serialized.</p>
<p>The method is defined as follows:</p>
<pre><code>ANY-ACCESS-MODIFIER Object writeReplace()
             throws ObjectStreamException;</code></pre>
<p>The <code>writeReplace</code> method is called when <code>ObjectOutputStream</code> is preparing to write the object to the stream. The <code>ObjectOutputStream</code> checks whether the class defines the <code>writeReplace</code> method. If the method is defined, the <code>writeReplace</code> method is called to allow the object to designate its replacement in the stream. The object returned should be either of the same type as the object passed in or an object that when read and resolved will result in an object of a type that is compatible with all references to the object. If it is not, a <code>ClassCastException</code> will occur when the type mismatch is discovered.</p>
<h2 id="the-useprotocolversion-method">2.6 The useProtocolVersion Method</h2>
<p>Due to a stream protocol change that was not backwards compatible, a mechanism has been added to enable the current Virtual Machine to write a serialization stream that is readable by a previous release. Of course, the problems that are corrected by the new stream format will exist when using the backwards compatible protocol.</p>
<p>Stream protocol versions are discussed in <a href="protocol.html#stream-protocol-versions">Section 6.3, &quot;Stream Protocol Versions&quot;</a>.</p>
</main><footer class="legal-footer"><hr/><a href="../../legal/copyright.html">Copyright</a> &copy; 1993, 2021, Oracle and/or its affiliates, 500 Oracle Parkway, Redwood Shores, CA 94065 USA.<br>All rights reserved. Use is subject to <a href="https://www.oracle.com/java/javase/terms/license/java17speclicense.html">license terms</a> and the <a href="https://www.oracle.com/technetwork/java/redist-137594.html">documentation redistribution policy</a>. <!-- Version 17.0.2+8-LTS-86 --></footer>
</body>
</html>